package com.useful.core.csv;

import cn.hutool.core.io.IoUtil;
import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
import com.useful.core.constant.GlobalConstant;
import com.useful.core.pool.CharPool;
import com.useful.core.utils.Charsets;
import lombok.experimental.UtilityClass;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PushbackInputStream;
import java.util.List;

/**
 * @author : wenchao.long
 * @date : Created in 2021/9/22 13:43 周三
 * @description :
 */
@UtilityClass
public class CsvUtil {

    /**
     * 读取csv文件 获取csv数据
     * {@link com.opencsv.bean.CsvBindByName}
     * <p>
     *
     * public class example{
     * '@CsvBindByName(column = "xxx")'
     * private String name
     * }
     * </p>
     *
     * @param file  文件
     * @param clazz 绑定的bean 每一个属性都要绑定@CsvBindByName
     * @param <T>   泛型
     * @return List
     */
    public <T> List<T> list(MultipartFile file, Class<T> clazz) {
        InputStreamReader isr = null;
        InputStream is = null;
        try {
            is = file.getInputStream();
            isr = new InputStreamReader(getIs(is), Charsets.GBK);
            HeaderColumnNameMappingStrategy<T> strategy = new HeaderColumnNameMappingStrategy<>();
            strategy.setType(clazz);

            CsvToBean<T> csvToBean = new CsvToBeanBuilder<T>(isr)
                    .withMappingStrategy(strategy)
                    .build();
            return csvToBean.parse();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                IoUtil.close(is);
            }
            if (isr != null) {
                IoUtil.close(isr);
            }
        }
        return null;
    }

    private InputStream getIs(InputStream is) throws IOException {
        PushbackInputStream pis = new PushbackInputStream(is);
        int ch = pis.read();
        if (ch != CharPool.EF) {
            pis.unread(ch);
        } else if ((ch = pis.read()) != CharPool.BB) {
            pis.unread(ch);
            pis.unread(CharPool.EF_);
        } else if (pis.read() != CharPool.BF) {
            throw new IOException(GlobalConstant.FILE_EXCEPTION);
        }
        return pis;
    }
}
